package com.hrt.datasender.datastorage.strategy.monitordata;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import com.hrt.datasender.datadao.model.*;
import com.hrt.datasender.datadao.service.*;
import com.hrt.datasender.process.strategy.hj212.util.DataType;
import com.hrt.datasender.web.WebMain;
import com.hrt.datasender.web.bcmonitorparamdict.BcMonitorParamDictService;
import com.hrt.datasender.web.operInfo.OperInfoService;
import org.quartz.JobExecutionContext;

import com.btcode.common.MyLog;
import com.btcode.db.executer.IDataExecuter;
import com.btcode.db.result.Row;
import com.btcode.log.ILog;
import com.btcode.orm.executer.IORMExecuter;
import com.btcode.orm.model.IModel;
import com.btcode.schedule.ScheduleManager;
import com.btcode.schedule.SingleInstanceJob;
import com.hrt.datasender.datastorage.strategy.IStorageStrategy;
import com.hrt.db.DBManager;

/**
 * 监测类型的数据策略基类
 * 
 * @author gislin
 *
 */
public abstract class MonitorDataStrategy extends SingleInstanceJob implements IStorageStrategy {

    protected ILog log;

    @Override
    public void init() {
        log = MyLog.getInstance().getLogger(this.getClass().getName());
        registerStorageShedule();
        //createTable();
        registerClearShedule();
    }

    public abstract void registerClearShedule();

    @Override
    public void initJob(JobExecutionContext arg0) {
        log = MyLog.getInstance().getLogger(this.getClass().getName());
    }

    @Override
    public void myExecute(JobExecutionContext arg0) {
        try {
            List<String > parmList =BcDeviceMonitorParamService.getInstance().getMonitorParam();
            Calendar cal = Calendar.getInstance();
            List<IModel> models = getStorageData(cal,parmList);

            if (models == null || models.size() <= 0) {
                log.info(getShowName() + "无数据生成");
                OperInfoService.getInstance().info("注意：未获取到仪器数据，" +getShowName() + "无数据生成");
            } 
            else {
                log.info(getShowName() + "数据入库,记录数:" + models.size());
                OperInfoService.getInstance().info(getShowName() + "数据入库,记录数:" + models.size());
            }

            IORMExecuter ormExecuter = DBManager.getORMExecuter();
            ormExecuter.creates(models);

        } 
        catch (Exception e) {
            log.error(getShowName() + "生成出错", e);
        }
    }

    @Override
    public List<Row> getSendData(BcSendPlatformModel sendPlatForm) {

        Long readySendDatatime = getReadySendDataTime(sendPlatForm);

        if (readySendDatatime == null) {
            return null;
        }

        List<Row> result = getData(sendPlatForm, readySendDatatime);

        return result;
    }

    /**
     * 获取准备好要发送的数据时间
     * 
     * @return
     */
    protected Long getReadySendDataTime(BcSendPlatformModel platform) {
        Date startDate = getLastSendTime(platform);

        String sql;
        if("mysql".equals(WebMain.DBTYPE)){
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String dataTime = sdf.format(startDate);
            sql = "SELECT * FROM " + getStoageTable() + " WHERE DATATIME > '" + dataTime
                + "' ORDER BY DATATIME ASC LIMIT 0,1";
        }
        else{
            sql = "SELECT * FROM " + getStoageTable() + " WHERE DATATIME > " + startDate.getTime()
                + " ORDER BY DATATIME ASC LIMIT 0,1";
        }


        List<Row> list = DBManager.getDataExecuter().queryList(sql, null);

        if (list.size() < 1) {
            return null;
        }

        long firstDate;
        if("mysql".equals(WebMain.DBTYPE)){
            Date test = list.get(0).getDate("DATATIME");
            firstDate = test.getTime();
        }
        else{
            firstDate = (long) list.get(0).get("DATATIME");
        }
        return firstDate;
    }

    public List<Row> getData(BcSendPlatformModel sendPlatForm, Long readySendDatatime) {

        String[] params = BcSendPlatformParamService.getInstance().getPlatformParam(sendPlatForm.getIp(),
                sendPlatForm.getPort());

        if (params.length < 1) {
            return null;
        }

        StringBuffer paramStr = new StringBuffer("(");

        for (int i = 0; i < params.length; i++) {
            paramStr.append("'" + params[i] + "',");
        }

        paramStr.deleteCharAt(paramStr.length() - 1);
        paramStr.append(")");

        String sql;
        if("mysql".equals(WebMain.DBTYPE)){
            Date date = new Date(readySendDatatime);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String dataTime = sdf.format(date);
            sql = "SELECT * FROM " + getStoageTable() + " WHERE PARAM_CODE_BUS IN " + paramStr + " AND DATATIME = '"
                + dataTime + "'";
        }
        else{
            sql = "SELECT * FROM " + getStoageTable() + " WHERE PARAM_CODE_BUS IN " + paramStr + " AND DATATIME = "
                + readySendDatatime;
        }
        List<Row> result = DBManager.getDataExecuter().queryList(sql, null);

        return result;
    }

    public void createTable() {

        IDataExecuter sqlletExecuter = DBManager.getDataExecuter();
        String tabesql = "SELECT * FROM sqlite_master WHERE type='table' AND name ='" + getStoageTable() + "'";

        List<Row> rows = sqlletExecuter.queryList(tabesql, null);

        if (rows != null && rows.size() > 0) {
            log.info(getStoageTable() + "表已存在！");
        }
        else {
            String sql = " CREATE TABLE " + getStoageTable() + "(" + "DATA_ID TEXT PRIMARY KEY NOT NULL,"
                    + "PARAM_CODE_BUS TEXT," + "MEAS_RE DOUBLE," + "MEAS_MIN DOUBLE," + "MEAS_MAX DOUBLE,"
                    + "MEAS_AVG DOUBLE," + "MEAS_ZS DOUBLE," + "MEAS_ZS_MIN DOUBLE," + "MEAS_ZS_MAX DOUBLE,"
                    + "MEAS_ZS_AVG DOUBLE," + "MEAS_PL DOUBLE," + "FLAG TEXT," + "DATATIME DATETIME,"
                    + "CREATETIME DATETIME," + "DATATIME_TEXT text," + "CREATETIME_TEXT text" + ")";

            sqlletExecuter.create(sql, null);
            log.info("表" + getStoageTable() + "创建成功！");
        }
    };

    /**
     * 获取最后读取的时间
     * 
     * @return
     */
    public Date getLastSendTime(BcSendPlatformModel platform) {
        Date result = BdSendRecordService.getInstance().getLastSendDate(getDataType(), platform.getIp(),
                platform.getPort());
        return result;
    }

    /**
     * 获取最后读取的时间
     * 
     * @return
     */
    public Date getLastReadTime() {
        Date result = BdSourceReadRecordService.getInstance().getLastReadTime(getStrategyId());
        return result;
    }

    /**
     * 初始化读取记录
     */
    public void initReadRecord() {
        BdSourceReadRecordService.getInstance().initReadRecord(getStrategyId(), getDataType());
    }

    /**
     * 更新读取记录
     */
    public void updateReadRecord(Date date) {
        BdSourceReadRecordService.getInstance().updateReadRecord(getStrategyId(), date);
    }

    public void registerStorageShedule() {
        ScheduleManager.getInstance().addJob(getClass(), getConsStr());
    };

    public abstract String getConsStr();

    /**
     * 判断数字是否为空、无效
     * 
     * @param val
     * @return
     */
    protected boolean isEmpty(Double val) {

        if (val == null) {
            return false;
        }

        if (val.isNaN()) {
            return false;
        }

        return true;
    }

    /**
     * 根据取值规则获取值
     * @param valueRule
     * @param param
     * @param startTime
     * @param dataTime
     * @param dataSource  数据源
     * @return
     */
    public Double getValueByRule(String valueRule, String param, Calendar startTime, Calendar dataTime,
                                 String dataSource,DataType dataType){
        // 1：当前值 2：算术平均 3：区间累计 4：小时、天加权，分钟算术均值 5:分钟、小时当前值，天数据加权
        Double result = 0.0;
        try{
            switch (valueRule){
                case "1":
                    result = BdSourceService.getLastData(param, startTime, dataTime);
                    break;
                case "2":
                    result = BdSourceService.getArithmeticAvg(param, startTime, dataTime,dataSource);
                    break;
                case "3":
                    result = BdSourceService.getIntervalFlow(param, startTime, dataTime);
                    break;
                case "4":
                    if(DataType.minute.equals(dataType)){
                        result = BdSourceService.getArithmeticAvg(param, startTime, dataTime,dataSource);
                    }
                    else{

                        result = BdSourceService.getWeightAvg(param, startTime, dataTime,dataSource);
                    }
                    break;
                case "5":
                    //判断当前数据是分钟、小时还是天数据，差一步判断
                    if(DataType.day.equals(dataType)){
                        result = BdSourceService.getWeightAvg(param, startTime, dataTime,dataSource);
                    }
                    else{
                        result = BdSourceService.getLastData(param, startTime, dataTime);
                    }
                    break;
                default:
                    result = BdSourceService.getLastData(param, startTime, dataTime);
                    break;
            }
        }
        catch (Exception e) {
            log.error("根据取值规则获取值出错", e);
        }
        return result;
    }

    /**
     *  获取到流量的数据，判断parmList中有没有包含区间流量参数
     * @param parmList
     * @param dataSource
     * @param calStart
     * @param cal
     * @return
     */
    public Double getFlowValue(List<String> parmList,String dataSource,Calendar calStart,Calendar cal){
        String flowField = "B01TOTAL";
        Double dFlow = null;
        try{
            if(parmList.contains(flowField)){
                //取出流量数据
                BcMonitorParamDictModel paramModel = new BcMonitorParamDictModel();
                paramModel.setParamCodeBus(flowField);
                paramModel = BcMonitorParamDictService.getInstance().getModel(paramModel);
                String valueRule = paramModel.getValueRule();
                dFlow = getValueByRule(valueRule,flowField, calStart, cal,dataSource, DataType.hour);
            }
        }
        catch (Exception e){
            log.error("获取流量数据出错", e);
        }
        return dFlow;
    }


    public List<Row> getData(BcSendPlatformModel sendPlatForm, Long readySendDatatime,Long endTime) {
        return null;
    }

    public List<Row> convertAccessData(List<Row> result, BcAccessTableModel models) {
        List<BcAccessParamModel> paramModels = BcAccessParamService.getInstance().getList();
        List<Row> dataResult = new ArrayList<>();
        for (Row row : result) {
            for (int j = 0; j < paramModels.size(); j++) {
                //AVG
                String paramMeas = row.getSafeString(paramModels.get(j).getAccessParam() + "_" + models.getMeas());
                double paramMeasD = 0;
                if (!"".equals(paramMeas)) {
                    paramMeasD = Double.parseDouble(paramMeas);
                }

                //COU
                String paramPL = row.getSafeString(paramModels.get(j).getAccessParam() + "_" + models.getTl());
                double paramPLD = 0;
                if (!"".equals(paramPL)) {
                    paramPLD = Double.parseDouble(paramPL);
                }

                //DATATIME
                Date dateTime = row.getDate(models.getDatatime());
                long time = dateTime.getTime();

                String paramMeasSigin = row
                        .getSafeString(paramModels.get(j).getAccessParam() + "_" + models.getMeassigin());
                String datatime = row.getSafeString(models.getDatatime());

                Row item = new Row();
                item.put("MEAS_PL", paramPLD);
                item.put("MEAS_RE", paramMeasD);
                item.put("DATA_ID", paramModels.get(j).getParamCodeBus() + datatime);
                item.put("PARAM_CODE_BUS", paramModels.get(j).getParamCodeBus());
                item.put("CREATETIME", new Date());
                item.put("DATATIME", time);
                item.put("FLAG", "N");
                dataResult.add(item);
            }
        }
        return dataResult;
    }
}
